/*
 *     Copyright 2025 The Dragonfly Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package util

import (
	"os"
	"sync"
)

var (
	// globalFileServer is the global file server instance.
	globalFileServer FileServer
	// once is the sync.Once instance for globalFileServer.
	once sync.Once
)

// NewFileServer creates a new file server which using the singleton pattern.
func NewFileServer() (FileServer, error) {
	var err error
	once.Do(func() {
		// currently only support dufs file server,
		// can be extended to support more file servers in the future.
		globalFileServer, err = newDufsFileServer()
	})

	return globalFileServer, err
}

// GetFileServer returns the global file server instance.
func GetFileServer() FileServer {
	return globalFileServer
}

// FileServer is the interface of file server for testing.
type FileServer interface {
	// GenerateFile generates a file by random data with the specified size.
	GenerateFile(size FileSize) (*File, error)

	// DeleteFile deletes the file by the file info.
	DeleteFile(info os.FileInfo) error

	// Purge deletes all files generated by the file server, it should be called after all tests.
	Purge() error
}

// fileServer represents the config of the file server.
type fileServer struct {
	// endpoint is the endpoint of the file server.
	endpoint string
	// localDir is the local temporary directory of the file server.
	localDir string
}

// FileServerOption is the type of the options of the file server.
type FileServerOption func(*fileServer)

// WithFileServerEndpoint sets the endpoint of the file server.
func WithFileServerEndpoint(endpoint string) FileServerOption {
	return func(o *fileServer) {
		o.endpoint = endpoint
	}
}

// WithFileServerLocalDir sets the local temporary directory of the file server.
func WithFileServerLocalDir(localDir string) FileServerOption {
	return func(o *fileServer) {
		o.localDir = localDir
	}
}
